package top.hcode.hoj.utils;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.nutz.http.*;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.meta.Pair;

import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 使用 Nutz 的 Http 模块封装，增加自定义拦截链，cookie管理
 *
 * @author orangej
 * @since 2024/12/15
 */
@Slf4j
public class NutzHttpClient {

    private static final String RetryHeaderName = "x-retry";

    @Getter
    private InterceptorChain chain = new InterceptorChain();

    @Getter
    private MyCookie cookie = new MyCookie();

    @Setter
    private int timeout = 6000; // 单位毫秒

    @Setter
    private String userAgent;   // 设置 user-agent

    public NutzHttpClient() {
        cookie.setDebug(true);
        chain.addInterceptor(cookie);
    }

    public NutzHttpClient addInterceptor(HttpReqRespInterceptor interceptor) {
        chain.addInterceptor(interceptor);
        return this;
    }

    public Map<String, String> cookies() {
        return cookie.get();
    }

    public NutzHttpClient cookies(List<HttpCookie> cookieList) {
        if (Lang.isNotEmpty(cookieList)) {
            for (HttpCookie httpCookie : cookieList) {
                cookies(httpCookie.getName(), httpCookie.getValue());
            }
        }

        return this;
    }

    public String cookies(String name) {
        return cookie.get(name);
    }

    public NutzHttpClient cookies(String name, String value) {
        cookie.set(name, value);
        return this;
    }

    public NutzHttpClient cookies(Map<String, String> values) {
        if (values != null) {
            values.forEach(cookie::set);
        }
        return this;
    }

    public Response get(String url) {
        Request request = Request.get(url);
        return sendRequest(request);
    }

    public Response postJson(String url, Object body) {
        Request request = Request.post(url)
                .setData(Json.toJson(body));
        request.getHeader().set("Content-Type", "application/json");
        return sendRequest(request);
    }

    public Response sendRequest(Request request) {
        if (Strings.isNotBlank(userAgent)) {
            request.getHeader().set("User-Agent", userAgent);
        }

        // 发送请求
        Response response = Sender.create(request)
                .setFollowRedirects(false)
                .setInterceptor(chain)
                .setTimeout(timeout)
                .send();

        // 处理重定向（拦截器会自动更新cookie）
        int status = response.getStatus();
        boolean isRedirect = status == 302 || status == 307;
        if (isRedirect && request.getHeader().get(RetryHeaderName) == null) {
            String location = response.getHeader().get("Location");
            log.info("status:{}, redirect to: {}", status, location);

            request.setUrl(location);
            request.header(RetryHeaderName, "1");
            return sendRequest(request);    // 递归重发请求
        }

        return response;
    }

    static class InterceptorChain implements HttpReqRespInterceptor {

        private List<HttpReqRespInterceptor> interceptorList = new ArrayList<>();

        public InterceptorChain addInterceptor(HttpReqRespInterceptor interceptor) {
            interceptorList.add(interceptor);
            return this;
        }

        @Override
        public void beforeConnect(Request request) {
            request.getHeader().remove(RetryHeaderName);
            for (HttpReqRespInterceptor interceptor : interceptorList) {
                interceptor.beforeConnect(request);
            }
        }

        @Override
        public void afterConnect(Request request, HttpURLConnection conn) {
            for (HttpReqRespInterceptor interceptor : interceptorList) {
                interceptor.afterConnect(request, conn);
            }
        }

        @Override
        public void afterResponse(Request request, HttpURLConnection conn, Response response) {
            for (HttpReqRespInterceptor interceptor : interceptorList) {
                interceptor.afterResponse(request, conn, response);
            }
        }
    }

    /**
     * 自定义的 Cookie 处理类，不存储实际的 Cookie 实例，仅存储名称和值
     */
    static class MyCookie extends Cookie {
        public Map<String, String> get() {
            return super.map;
        }

        private static final List<String> IGNORE_NAMES = Lang.list("expires", "path", "domain",
                "max-age", "secure", "httponly", "samesite");

        public void parse(String str) {
            if (debug) {
                log.debug("parse " + str);
            }
            String[] ss = Strings.splitIgnoreBlank(str, ";");
            for (String s : ss) {
                Pair<String> p = Pair.create(Strings.trim(s));
                String val = p.getValueString();
                if (val == null) {
                    val = "";
                }

                if (IGNORE_NAMES.contains(p.getName().toLowerCase())) {
                    continue;
                }

                if (debug) {
                    log.debug("add cookie [{}={}]", p.getName(), val);
                }
                map.put(p.getName(), val);
            }
        }
    }

}
